import { clsx } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: any[]) {
  return twMerge(clsx(inputs));
}

export function isNumber(val: unknown): val is number {
  return typeof val == "number";
}

export function isString(val: unknown): val is string {
  return typeof val == "string" || val instanceof String;
}

export function randStr(): string {
  return Math.random().toString(36).slice(-8);
}

export type OSType = "Windows" | "MacOS" | "Linux" | "Other";
export function getOs(): OSType {
  if (navigator.userAgent.indexOf("Win") != -1) {
    return "Windows";
  } else if (navigator.userAgent.indexOf("Mac") != -1) {
    return "MacOS";
  } else if (navigator.userAgent.indexOf("Linux") != -1) {
    return "Linux";
  }
  return "Other";
}

export function isMobile(): boolean {
  return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
    navigator.userAgent
  );
}

/**
 * 客户端文件下载函数
 * @param data 要下载的数据（Blob、ArrayBuffer或字符串）
 * @param filename 下载后的文件名
 * @param mimeType 文件的MIME类型
 */
export function downloadFile(
  data: Blob | ArrayBuffer | string,
  filename: string,
  mimeType?: string
): void {
  // 创建Blob对象
  const blob =
    data instanceof Blob
      ? data
      : new Blob([data instanceof ArrayBuffer ? data : String(data)], {
          type: mimeType || "application/octet-stream",
        });

  // 创建下载链接
  const url = URL.createObjectURL(blob);

  // 创建临时a标签并触发下载
  const link = document.createElement("a");
  link.href = url;
  link.download = filename;
  link.style.display = "none";

  // 添加到DOM，触发点击，然后移除
  document.body.appendChild(link);
  link.click();

  // 延迟释放URL对象
  setTimeout(() => {
    document.body.removeChild(link);
    URL.revokeObjectURL(url);
  }, 100);
}

export function toUrlParams(params: Record<string, any>) {
  return new URLSearchParams(params).toString();
}

export type Prettify<T> = {
  [K in keyof T]: T[K];
} & {};

export function omit<T extends object, K extends keyof T>(
  object: T,
  keys: readonly K[]
): Prettify<Omit<T, K>> {
  return Object.keys(object).reduce((obj, key) => {
    if (!keys.includes(key as K)) {
      (obj as any)[key] = object[key as keyof T];
    }
    return obj;
  }, {} as Omit<T, K>);
}
